// CompressDialog.cpp

#include "StdAfx.h"

#include "Common/String/StringConvert.h"

#include "Common/FileSystem/FileDir.h"
#include "Common/FileSystem/FileName.h"
#include "Common/System/System.h"

#include "Common/String/FormatUtils.h"
#include "../FileManager/HelpUtils.h"
#include "Common/FileSystem/SplitUtils.h"

#include "../Explorer/MyMessages.h"

#include "Common/App/AppRegistry.h"

#include "CompressDialog.h"

#include <algorithm>

#ifdef LANG
#include "Common/Lang/LangUtils.h"
#endif

#include "CompressDialogRes.h"

#define MY_SIZE_OF_ARRAY(x) (sizeof(x) / sizeof(x[0]))

using namespace Common;

#ifdef LANG
static Lang::CIDLangPair kIDLangPairs[] =
{
  { IDC_STATIC_COMPRESS_ARCHIVE, 0x02000D01 },
  { IDC_STATIC_COMPRESS_FORMAT, 0x02000D03 },
  { IDC_STATIC_COMPRESS_LEVEL, 0x02000D0B },
  { IDC_STATIC_COMPRESS_METHOD, 0x02000D04 },
  { IDC_STATIC_COMPRESS_DICTIONARY, 0x02000D0C },
  { IDC_STATIC_COMPRESS_ORDER, 0x02000D0D },
  { IDC_STATIC_COMPRESS_MEMORY, 0x02000D0E },
  { IDC_STATIC_COMPRESS_MEMORY_DE, 0x02000D0F },
  { IDC_STATIC_COMPRESS_THREADS, 0x02000D12 },
  { IDC_STATIC_COMPRESS_SOLID, 0x02000D13 },
  { IDC_STATIC_COMPRESS_VOLUME, 0x02000D40 },
  { IDC_STATIC_COMPRESS_PARAMETERS, 0x02000D06 },
  
  { IDC_STATIC_COMPRESS_UPDATE_MODE, 0x02000D02 },
  { IDC_STATIC_COMPRESS_OPTIONS, 0x02000D07 },
  { IDC_COMPRESS_SFX, 0x02000D08 },
  { IDC_COMPRESS_SHARED, 0x02000D16 },
  
  { IDC_COMPRESS_ENCRYPTION, 0x02000D10 },
  { IDC_STATIC_COMPRESS_PASSWORD1, 0x02000B01 },
  { IDC_STATIC_COMPRESS_PASSWORD2, 0x02000B03 },
  { IDC_COMPRESS_CHECK_SHOW_PASSWORD, 0x02000B02 },
  { IDC_STATIC_COMPRESS_ENCRYPTION_METHOD, 0x02000D11 },
  { IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, 0x02000D0A },

  { IDOK, 0x02000702 },
  { IDCANCEL, 0x02000710 },
  { IDHELP, 0x02000720 }
};
#endif

using namespace System;


static const int kHistorySize = 20;

static LPCWSTR kExeExt = _T(".exe");
static LPCWSTR k7zFormat = _T("7z");

struct CLevelInfo
{
  UINT32 ResourceID;
  UINT32 LangID;
};

enum ELevel
{
  kStore = 0,
  kFastest = 1,
  kFast = 3,
  kNormal = 5,
  kMaximum = 7,
  kUltra = 9
};

static const CLevelInfo g_Levels[] =
{
  { IDS_METHOD_STORE, 0x02000D81 },
  { IDS_METHOD_FASTEST, 0x02000D85 },
  { 0, 0 },
  { IDS_METHOD_FAST, 0x02000D84 },
  { 0, 0 },
  { IDS_METHOD_NORMAL, 0x02000D82 },
  { 0, 0 },
  { IDS_METHOD_MAXIMUM, 0x02000D83 },
  { 0, 0 },
  { IDS_METHOD_ULTRA, 0x02000D86 }
};

enum EMethodID
{
  kCopy,
  kLZMA,
  kLZMA2,
  kPPMd,
  kBZip2,
  kDeflate,
  kDeflate64,
  kPPMdZip
};

static const LPCWSTR kMethodsNames[] =
{
  _T("Copy"),
  _T("LZMA"),
  _T("LZMA2"),
  _T("PPMd"),
  _T("BZip2"),
  _T("Deflate"),
  _T("Deflate64"),
  _T("PPMd")
};

static const EMethodID g_7zMethods[] =
{
  kLZMA,
  kLZMA2,
  kPPMd,
  kBZip2
};

static const EMethodID g_7zSfxMethods[] =
{
  kCopy,
  kLZMA,
  kLZMA2,
  kPPMd
};

static EMethodID g_ZipMethods[] =
{
  kDeflate,
  kDeflate64,
  kBZip2,
  kLZMA,
  kPPMdZip
};

static EMethodID g_GZipMethods[] =
{
  kDeflate
};

static EMethodID g_BZip2Methods[] =
{
  kBZip2
};

static EMethodID g_XzMethods[] =
{
  kLZMA2
};

struct CFormatInfo
{
  LPCWSTR Name;
  UINT32 LevelsMask;
  const EMethodID *MathodIDs;
  int NumMethods;
  bool Filter;
  bool Solid;
  bool MultiThread;
  bool SFX;
  bool Encrypt;
  bool EncryptFileNames;
};

#define METHODS_PAIR(x) x, MY_SIZE_OF_ARRAY(x)

static const CFormatInfo g_Formats[] =
{
  {
	_T(""),
	(1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
	0, 0,
	false, false, false, false, false, false
  },
  {
	k7zFormat,
	(1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
	METHODS_PAIR(g_7zMethods),
	true, true, true, true, true, true
  },
  {
	_T("Zip"),
	(1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
	METHODS_PAIR(g_ZipMethods),
	false, false, true, false, true, false
  },
  {
	_T("GZip"),
	(1 << 1) | (1 << 5) | (1 << 7) | (1 << 9),
	METHODS_PAIR(g_GZipMethods),
	false, false, false, false, false, false
  },
  {
	_T("BZip2"),
	(1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
	METHODS_PAIR(g_BZip2Methods),
	false, false, true, false, false, false
  },
  {
	_T("xz"),
	(1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
	METHODS_PAIR(g_XzMethods),
	false, false, true, false, false, false
  },
  {
	_T("Tar"),
	(1 << 0),
	0, 0,
	false, false, false, false, false, false
  },
  {
	_T("wim"),
	(1 << 0),
	0, 0,
	false, false, false, false, false, false
  }
};

static bool IsMethodSupportedBySfx(int methodID)
{
  for (int i = 0; i < MY_SIZE_OF_ARRAY(g_7zSfxMethods); i++)
	if (methodID == g_7zSfxMethods[i])
	  return true;
  return false;
}

static UINT64 GetMaxRamSizeForProgram()
{
  UINT64 physSize = System::GetRamSize();
  const UINT64 kMinSysSize = (1 << 24);
  if (physSize <= kMinSysSize)
	physSize = 0;
  else
	physSize -= kMinSysSize;
  const UINT64 kMinUseSize = (1 << 24);
  if (physSize < kMinUseSize)
	physSize = kMinUseSize;
  return physSize;
}

LRESULT CCompressDialog::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
  #ifdef LANG
  Lang::LangSetWindowText(HWND(*this), 0x02000D00);
  Lang::LangSetDlgItemsText(HWND(*this), kIDLangPairs, MY_SIZE_OF_ARRAY(kIDLangPairs) );
  #endif
  _password1Control.Attach(GetDlgItem(IDC_COMPRESS_EDIT_PASSWORD1));
  _password2Control.Attach(GetDlgItem(IDC_COMPRESS_EDIT_PASSWORD2));
  _password1Control.SetWindowText(Info.Password);
  _password2Control.SetWindowText(Info.Password);
  _encryptionMethod.Attach(GetDlgItem(IDC_COMPRESS_COMBO_ENCRYPTION_METHOD));

  m_ArchivePath.Attach(GetDlgItem(IDC_COMPRESS_COMBO_ARCHIVE));
  m_Format.Attach(GetDlgItem(IDC_COMPRESS_COMBO_FORMAT));
  m_Level.Attach(GetDlgItem(IDC_COMPRESS_COMBO_LEVEL));
  m_Method.Attach(GetDlgItem(IDC_COMPRESS_COMBO_METHOD));
  m_Dictionary.Attach(GetDlgItem(IDC_COMPRESS_COMBO_DICTIONARY));
  m_Order.Attach(GetDlgItem(IDC_COMPRESS_COMBO_ORDER));
  m_Solid.Attach(GetDlgItem(IDC_COMPRESS_COMBO_SOLID));
  m_NumThreads.Attach(GetDlgItem(IDC_COMPRESS_COMBO_THREADS));
  
  m_UpdateMode.Attach(GetDlgItem(IDC_COMPRESS_COMBO_UPDATE_MODE));
  m_Volume.Attach(GetDlgItem(IDC_COMPRESS_COMBO_VOLUME));
  m_Params.Attach(GetDlgItem(IDC_COMPRESS_EDIT_PARAMETERS));

  FileSystem::AddVolumeItems(m_Volume);

  m_RegistryInfo.Load();
  CheckDlgButton(IDC_COMPRESS_CHECK_SHOW_PASSWORD, m_RegistryInfo.ShowPassword ? BST_CHECKED : BST_UNCHECKED);
  CheckDlgButton(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders? BST_CHECKED : BST_UNCHECKED);

  UpdatePasswordControl();

  Info.FormatIndex = -1;
  size_t i;
  for (i = 0; i < ArcIndices.size(); i++)
  {
	int arcIndex = ArcIndices[i];
	const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[arcIndex];
	int index = (int)m_Format.AddString(ai.Name);
	m_Format.SetItemData(index, arcIndex);
	if (ai.Name.CompareNoCase(m_RegistryInfo.ArcType) == 0 || i == 0)
	{
	  m_Format.SetCurSel(index);
	  Info.FormatIndex = arcIndex;
	}
  }

  SetArchiveName(Info.ArchiveName);
  SetLevel();
  SetParams();
  
  for (i = 0; i < m_RegistryInfo.ArcPaths.size() && i < kHistorySize; i++)
	m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]);

  m_UpdateMode.AddString(Lang::LangString(IDS_COMPRESS_UPDATE_MODE_ADD, 0x02000DA1));
  m_UpdateMode.AddString(Lang::LangString(IDS_COMPRESS_UPDATE_MODE_UPDATE, 0x02000DA2));
  m_UpdateMode.AddString(Lang::LangString(IDS_COMPRESS_UPDATE_MODE_FRESH, 0x02000DA3));
  m_UpdateMode.AddString(Lang::LangString(IDS_COMPRESS_UPDATE_MODE_SYNCHRONIZE, 0x02000DA4));

  m_UpdateMode.SetCurSel(0);

  SetSolidBlockSize();
  SetNumThreads();

  TCHAR s[40] = { TEXT('/'), TEXT(' '), 0 };
  _ultot(System::GetNumberOfProcessors(), s + 2, 10);
  SetDlgItemText(IDC_COMPRESS_HARDWARE_THREADS, s);

  CheckDlgButton(IDC_COMPRESS_SFX, Info.SFXMode ? BST_CHECKED : BST_UNCHECKED);	
  CheckDlgButton(IDC_COMPRESS_SHARED, Info.OpenShareForWrite ? BST_CHECKED : BST_UNCHECKED);
  
  CheckControlsEnable();

  OnButtonSFX();

  SetEncryptionMethod();
  SetMemoryUsage();

  CenterWindow(GetParent());
  return TRUE;
}

namespace CompressDialog
{
  bool CInfo::GetFullPathName(CString &result) const
  {
	#ifndef UNDER_CE
	FileSystem::SetCurrentDirectory(CurrentDirPrefix);
	#endif
	return FileSystem::GetFullPathName(ArchiveName, result);
  }
}

void CCompressDialog::UpdatePasswordControl()
{
  bool showPassword = IsShowPasswordChecked();
  TCHAR c = showPassword ? 0: TEXT('*');
  _password1Control.SetPasswordChar(c);
  _password2Control.SetPasswordChar(c);
  CString password;
  _password1Control.GetWindowText(password);
  _password1Control.SetWindowText(password);
  _password2Control.GetWindowText(password);
  _password2Control.SetWindowText(password);

  int cmdShow = showPassword ? SW_HIDE : SW_SHOW;	
  ::ShowWindow(GetDlgItem(IDC_STATIC_COMPRESS_PASSWORD2), cmdShow);
  _password2Control.ShowWindow(cmdShow);
}


void CCompressDialog::CheckSFXControlsEnable()
{
  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  bool enable = fi.SFX;
  if (enable)
  {
	int methodID = GetMethodID();
	enable = (methodID == -1 || IsMethodSupportedBySfx(methodID));
  }
  if (!enable)
	CheckDlgButton(IDC_COMPRESS_SFX, BST_UNCHECKED);		
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_SFX), enable);
}

void CCompressDialog::CheckVolumeEnable()
{
  bool isSFX = IsSFX();
  m_Volume.EnableWindow(!isSFX);
  if (isSFX)
	m_Volume.SetWindowText(TEXT(""));
}

void CCompressDialog::CheckControlsEnable()
{
  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  Info.SolidIsSpecified = fi.Solid;
  bool multiThreadEnable = fi.MultiThread;
  Info.MultiThreadIsAllowed = multiThreadEnable;
  Info.EncryptHeadersIsAllowed = fi.EncryptFileNames;
  
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_COMBO_SOLID), fi.Solid);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_COMBO_THREADS), multiThreadEnable);
  CheckSFXControlsEnable();
  CheckVolumeEnable();

  ::EnableWindow(GetDlgItem(IDC_COMPRESS_ENCRYPTION), fi.Encrypt);

  ::EnableWindow(GetDlgItem(IDC_STATIC_COMPRESS_PASSWORD1), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_STATIC_COMPRESS_PASSWORD2), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_EDIT_PASSWORD1), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_EDIT_PASSWORD2), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_CHECK_SHOW_PASSWORD), fi.Encrypt);

  ::EnableWindow(GetDlgItem(IDC_STATIC_COMPRESS_ENCRYPTION_METHOD), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_COMBO_ENCRYPTION_METHOD), fi.Encrypt);
  ::EnableWindow(GetDlgItem(IDC_COMPRESS_COMBO_SOLID), fi.EncryptFileNames);

  ::ShowWindow(GetDlgItem(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES), fi.EncryptFileNames ? SW_SHOW : SW_HIDE);
}

bool CCompressDialog::IsSFX()
{
  CWindow sfxButton = GetDlgItem(IDC_COMPRESS_SFX);
  return sfxButton.IsWindowEnabled() && BST_CHECKED == IsDlgButtonChecked(IDC_COMPRESS_SFX);
}

void CCompressDialog::OnButtonSFX()
{
  SetMethod(GetMethodID());

  CString fileName;
  m_ArchivePath.GetWindowText(fileName);
  int dotPos = fileName.ReverseFind(_T('.'));
  int slashPos = fileName.ReverseFind(CHAR_PATH_SEPARATOR);
  if (dotPos < 0 || dotPos <= slashPos)
	dotPos = -1;
  if (IsSFX())
  {
	if (dotPos >= 0)
	  fileName = fileName.Left(dotPos);
	fileName += kExeExt;
	m_ArchivePath.SetWindowText(fileName);
  }
  else
  {
	if (dotPos >= 0)
	{
	  CString ext = fileName.Mid(dotPos);
	  if (ext.CompareNoCase(kExeExt) == 0)
	  {
		fileName = fileName.Left(dotPos);
		m_ArchivePath.SetWindowText(fileName);
	  }
	}
	SetArchiveName2(false); // it's for OnInit
  }

  CheckVolumeEnable();
}

void CCompressDialog::OnButtonSetArchive()
{
  CString fileName;
  m_ArchivePath.GetWindowText(fileName);
  fileName.Trim();
  Info.ArchiveName = fileName;
  CString fullFileName;
  if (!Info.GetFullPathName(fullFileName))
  {
	fullFileName = Info.ArchiveName;
	return;
  }
  CString title = Lang::LangString(IDS_COMPRESS_SET_ARCHIVE_DIALOG_TITLE, 0x02000D90);
  CString s = Lang::LangString(IDS_OPEN_TYPE_ALL_FILES, 0x02000DB1);
  s += _T(" (*.*)");
  

  CFolderDialog dlg(*this, title, BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE| BIF_STATUSTEXT);
  if(!fullFileName.IsEmpty())
	  dlg.SetInitialFolder(fullFileName);
  if (IDOK == dlg.DoModal())
  {
	 CString resPath(dlg.GetFolderPath());
	 m_ArchivePath.SetWindowText(resPath);
  }

  
}

// in ExtractDialog.cpp
extern void AddUniqueString(CStringVector &strings, const CString &srcString);

static bool IsAsciiString(const CString &s)
{
  for (int i = 0; i < s.GetLength(); i++)
  {
	wchar_t c = s[i];
	if (c < 0x20 || c > 0x7F)
	  return false;
  }
  return true;
}

LRESULT CCompressDialog::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
  _password1Control.GetWindowText(Info.Password);
  if (IsZipFormat())
  {
	if (!IsAsciiString(Info.Password))
	{
	  ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII, 0x02000B11);
	  return 1;
	}
	CString method = GetEncryptionMethodSpec();
	method.MakeUpper();
	if (method.Find(_T("AES")) == 0)
	{
	  if (Info.Password.GetLength() > 99)
	  {
		ShowErrorMessageHwndRes(*this, IDS_PASSWORD_IS_TOO_LONG, 0x02000B12);
		return 1;
	  }
	}
  }
  if (!IsShowPasswordChecked())
  {
	CString password2;
	_password2Control.GetWindowText(password2);
	if (password2 != Info.Password)
	{
	  ShowErrorMessageHwndRes(*this, IDS_PASSWORD_PASSWORDS_DO_NOT_MATCH, 0x02000B10);
	  return 1 ;
	}
  }

  SaveOptionsInMem();
  CString s;
  m_ArchivePath.GetWindowText(s);
  s.Trim();
  m_RegistryInfo.ArcPaths.clear();
  AddUniqueString(m_RegistryInfo.ArcPaths, s);
  Info.ArchiveName = s;
  Info.UpdateMode = CompressDialog::UpdateMode::EEnum(m_UpdateMode.GetCurSel());

  Info.Level = GetLevelSpec();
  Info.Dictionary = GetDictionarySpec();
  Info.Order = GetOrderSpec();
  Info.OrderMode = GetOrderMode();
  Info.NumThreads = GetNumThreadsSpec();

  UINT32 solidLogSize = GetBlockSizeSpec();
  Info.SolidBlockSize = 0;
  if (solidLogSize > 0 && solidLogSize != (UINT32)-1)
	Info.SolidBlockSize = (solidLogSize >= 64) ? (UINT64)(INT64)-1 : ((UINT64)1 << solidLogSize);

  Info.Method = GetMethodSpec();
  Info.EncryptionMethod = GetEncryptionMethodSpec();
  Info.FormatIndex = GetFormatIndex();
  Info.SFXMode = IsSFX();
  Info.OpenShareForWrite = (BST_CHECKED == IsDlgButtonChecked(IDC_COMPRESS_SHARED));

  m_RegistryInfo.EncryptHeaders = Info.EncryptHeaders = (BST_CHECKED == IsDlgButtonChecked(IDC_COMPRESS_CHECK_ENCRYPT_FILE_NAMES));

  m_Params.GetWindowText(Info.Options);
  CString volumeString;
  m_Volume.GetWindowText(volumeString);
  volumeString.Trim();
  Info.VolumeSizes.clear();
  if (!volumeString.IsEmpty())
  {
	if (!FileSystem::ParseVolumeSizes(volumeString, Info.VolumeSizes))
	{
	  ShowErrorMessageHwndRes(*this, IDS_COMPRESS_INCORRECT_VOLUME_SIZE, 0x02000D41);
	  return 1;
	}
	if (!Info.VolumeSizes.empty())
	{
	  const UINT64 volumeSize = Info.VolumeSizes.back();
	  if (volumeSize < (100 << 10))
	  {
		TCHAR s[32];
		_ui64tot(volumeSize, s, 10);
		if (::MessageBox(*this, String::PatternFormat(IDS_COMPRESS_SPLIT_CONFIRM_MESSAGE, 0x02000D42, s),
			_T("7-Zip"), MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES)
		  return 1 ;
	  }
	}
  }

  for (int i = 0; i < m_ArchivePath.GetCount(); i++)
  {
	CString sTemp;
	m_ArchivePath.GetLBText(i, sTemp);
	sTemp.Trim();
	AddUniqueString(m_RegistryInfo.ArcPaths, sTemp);
  }
  if (m_RegistryInfo.ArcPaths.size() > kHistorySize)
	  m_RegistryInfo.ArcPaths.pop_back();
  
  m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name;
  m_RegistryInfo.ShowPassword = IsShowPasswordChecked();

  m_RegistryInfo.Save();
  
  EndDialog(wID);
  return 0;
}

static LPCWSTR kHelpTopic = _T("fm/plugins/7-zip/add.htm");

LRESULT CCompressDialog::OnHelp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
  ShowHelpWindow(NULL, kHelpTopic);
	return 0;
}

LRESULT CCompressDialog::OnSelectionChange(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	switch(wID)
	{
	  case IDC_COMPRESS_COMBO_FORMAT:
	  {
		bool isSFX = IsSFX();
		SaveOptionsInMem();
		SetLevel();
		SetSolidBlockSize();
		SetNumThreads();
		SetParams();
		CheckControlsEnable();
		SetArchiveName2(isSFX);
		SetEncryptionMethod();
		SetMemoryUsage();
		return TRUE;
	  }
	  case IDC_COMPRESS_COMBO_LEVEL:
	  {
		const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
		int index = FindRegistryFormatAlways(ai.Name);
		Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
		fo.ResetForLevelChange();
		SetMethod();
		SetSolidBlockSize();
		SetNumThreads();
		CheckSFXNameChange();
		SetMemoryUsage();
		return TRUE;
	  }
	  case IDC_COMPRESS_COMBO_METHOD:
	  {
		SetDictionary();
		SetOrder();
		SetSolidBlockSize();
		SetNumThreads();
		CheckSFXNameChange();
		SetMemoryUsage();
		return TRUE;
	  }
	  case IDC_COMPRESS_COMBO_DICTIONARY:
	  case IDC_COMPRESS_COMBO_ORDER:
	  {
		SetSolidBlockSize();
		SetMemoryUsage();
		return TRUE;
	  }
	  case IDC_COMPRESS_COMBO_THREADS:
	  {
		SetMemoryUsage();
		return TRUE;
	  }
  }
  return FALSE;
}

void CCompressDialog::CheckSFXNameChange()
{
  bool isSFX = IsSFX();
  CheckSFXControlsEnable();
  if (isSFX != IsSFX())
	SetArchiveName2(isSFX);
}

void CCompressDialog::SetArchiveName2(bool prevWasSFX)
{
  CString fileName;
  m_ArchivePath.GetWindowText(fileName);
  const Common::Archive::CArcInfoEx &prevArchiverInfo = (*ArcFormats)[m_PrevFormat];
  if (prevArchiverInfo.KeepName || Info.KeepName)
  {
	CString prevExtension = prevArchiverInfo.GetMainExt();
	if (prevWasSFX)
	  prevExtension = kExeExt;
	else
	  prevExtension = CString('.') + prevExtension;
	const int prevExtensionLen = prevExtension.GetLength();
	if (fileName.GetLength() >= prevExtensionLen)
	  if (fileName.Right(prevExtensionLen).CompareNoCase(prevExtension) == 0)
		fileName = fileName.Left(fileName.GetLength() - prevExtensionLen);
  }
  SetArchiveName(fileName);
}

// if type.KeepName then use OriginalFileName
// else if !KeepName remove extension
// add new extension

void CCompressDialog::SetArchiveName(const CString &name)
{
  CString fileName = name;
  Info.FormatIndex = GetFormatIndex();
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
  m_PrevFormat = Info.FormatIndex;
  if (ai.KeepName)
  {
	fileName = OriginalFileName;
  }
  else
  {
	if (!Info.KeepName)
	{
	  int dotPos = fileName.ReverseFind('.');
	  int slashPos = max(fileName.ReverseFind(CHAR_PATH_SEPARATOR), fileName.ReverseFind('/'));
	  if (dotPos >= 0 && dotPos > slashPos + 1)
		fileName = fileName.Left(dotPos);
	}
  }

  if (IsSFX())
	fileName += kExeExt;
  else
  {
	fileName += _T('.');
	fileName += ai.GetMainExt();
  }
  m_ArchivePath.SetWindowText(fileName);
}

size_t CCompressDialog::FindRegistryFormat(const CString &name)
{
  for (size_t i = 0; i < m_RegistryInfo.Formats.size(); i++)
  {
	const Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[i];
	if (name.CompareNoCase(String::GetUnicodeString(fo.FormatID)) == 0)
	  return i;
  }
  return -1;
}

size_t CCompressDialog::FindRegistryFormatAlways(const CString &name)
{
  size_t index = FindRegistryFormat(name);
  if (index == -1)
  {
	Archive::Compression::CFormatOptions fo;
	fo.FormatID = String::GetSystemString(name);
	m_RegistryInfo.Formats.push_back(fo);
	index = m_RegistryInfo.Formats.size() - 1;
  }
  return index;
}

int CCompressDialog::GetStaticFormatIndex()
{
  int formatIndex = GetFormatIndex();
  const Archive::CArcInfoEx &ai = (*ArcFormats)[formatIndex];
  for (int i = 0; i < MY_SIZE_OF_ARRAY(g_Formats); i++)
	if (ai.Name.CompareNoCase(g_Formats[i].Name) == 0)
	  return i;
  return 0; // -1;
}

void CCompressDialog::SetNearestSelectComboBox(CComboBox &comboBox, UINT32 value)
{
  for (int i = comboBox.GetCount() - 1; i >= 0; i--)
	if ((UINT32)comboBox.GetItemData(i) <= value)
	{
	  comboBox.SetCurSel(i);
	  return;
	}
  if (comboBox.GetCount() > 0)
	comboBox.SetCurSel(0);
}

void CCompressDialog::SetLevel()
{
  m_Level.ResetContent();
  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  UINT32 level = kNormal;
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	if (fo.Level <= kUltra)
	  level = fo.Level;
	else
	  level = kUltra;
  }
  int i;
  for (i = 0; i <= kUltra; i++)
  {
	if ((fi.LevelsMask & (1 << i)) != 0)
	{
	  const CLevelInfo &levelInfo = g_Levels[i];
	  int index = (int)m_Level.AddString(Lang::LangString(levelInfo.ResourceID, levelInfo.LangID));
	  m_Level.SetItemData(index, i);
	}
  }
  SetNearestSelectComboBox(m_Level, level);
  SetMethod();
}

void CCompressDialog::SetMethod(int keepMethodId)
{
  m_Method.ResetContent();
  UINT32 level = GetLevel();
  if (level == 0)
  {
	SetDictionary();
	SetOrder();
	return;
  }
  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  CString defaultMethod;
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	defaultMethod = fo.Method;
  }
  bool isSfx = IsSFX();
  bool weUseSameMethod = false;
  for (int m = 0; m < fi.NumMethods; m++)
  {
	EMethodID methodID = fi.MathodIDs[m];
	if (isSfx)
	  if (!IsMethodSupportedBySfx(methodID))
		continue;
	const LPCWSTR method = kMethodsNames[methodID];
	int itemIndex = (int)m_Method.AddString(String::GetSystemString(method));
	m_Method.SetItemData(itemIndex, methodID);
	if (keepMethodId == methodID)
	{
	  m_Method.SetCurSel(itemIndex);
	  weUseSameMethod = true;
	  continue;
	}
	if ((defaultMethod.CompareNoCase(method) == 0 || m == 0) && !weUseSameMethod)
	  m_Method.SetCurSel(itemIndex);
  }
  if (!weUseSameMethod)
  {
	SetDictionary();
	SetOrder();
  }
}

bool CCompressDialog::IsZipFormat()
{
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  return (ai.Name.CompareNoCase(_T("zip")) == 0);
}

void CCompressDialog::SetEncryptionMethod()
{
  _encryptionMethod.ResetContent();
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  if (ai.Name.CompareNoCase(_T("7z")) == 0)
  {
	_encryptionMethod.AddString(TEXT("AES-256"));
	_encryptionMethod.SetCurSel(0);
  }
  else if (ai.Name.CompareNoCase(_T("zip")) == 0)
  {
	size_t index = FindRegistryFormat(ai.Name);
	CString encryptionMethod;
	if (index != -1)
	{
	  const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	  encryptionMethod = fo.EncryptionMethod;
	}
	_encryptionMethod.AddString(TEXT("ZipCrypto"));
	_encryptionMethod.AddString(TEXT("AES-256"));
	_encryptionMethod.SetCurSel(encryptionMethod.Find(_T("AES")) == 0 ? 1 : 0);
  }
}

int CCompressDialog::GetMethodID()
{
  if (m_Method.GetCount() <= 0)
	return -1;
  return (int)(UINT32)m_Method.GetItemData(m_Method.GetCurSel());
}

CString CCompressDialog::GetMethodSpec()
{
  if (m_Method.GetCount() <= 1)
	return CString();
  return kMethodsNames[GetMethodID()];
}

CString CCompressDialog::GetEncryptionMethodSpec()
{
  if (_encryptionMethod.GetCount() <= 1)
	return CString();
  if (_encryptionMethod.GetCurSel() <= 0)
	return CString();
  CString result;
  _encryptionMethod.GetWindowText(result);
  result.Replace(_T("-"), _T(""));
  return result;
}

int CCompressDialog::AddDictionarySize(UINT32 size, bool kilo, bool maga)
{
  UINT32 sizePrint = size;
  if (kilo)
	sizePrint >>= 10;
  else if (maga)
	sizePrint >>= 20;
  TCHAR s[40];
  _ultot(sizePrint, s, 10);
  if (kilo)
	lstrcat(s, TEXT(" K"));
  else if (maga)
	lstrcat(s, TEXT(" M"));
  else
	lstrcat(s, TEXT(" "));
  lstrcat(s, TEXT("B"));
  int index = (int)m_Dictionary.AddString(s);
  m_Dictionary.SetItemData(index, size);
  return index;
}

int CCompressDialog::AddDictionarySize(UINT32 size)
{
  if (size > 0)
  {
	if ((size & 0xFFFFF) == 0)
	  return AddDictionarySize(size, false, true);
	if ((size & 0x3FF) == 0)
	  return AddDictionarySize(size, true, false);
  }
  return AddDictionarySize(size, false, false);
}

void CCompressDialog::SetDictionary()
{
  m_Dictionary.ResetContent();
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  UINT32 defaultDictionary = (UINT32)-1;
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	if (fo.Method.CompareNoCase(GetMethodSpec()) == 0)
	  defaultDictionary = fo.Dictionary;
  }
  int methodID = GetMethodID();
  UINT32 level = GetLevel2();
  if (methodID < 0)
	return;
  const UINT64 maxRamSize = GetMaxRamSizeForProgram();
  switch (methodID)
  {
	case kLZMA:
	case kLZMA2:
	{
	  static const UINT32 kMinDicSize = (1 << 16);
	  if (defaultDictionary == (UINT32)-1)
	  {
		if (level >= 9)      defaultDictionary = (1 << 26);
		else if (level >= 7) defaultDictionary = (1 << 25);
		else if (level >= 5) defaultDictionary = (1 << 24);
		else if (level >= 3) defaultDictionary = (1 << 20);
		else                 defaultDictionary = (kMinDicSize);
	  }
	  int i;
	  AddDictionarySize(kMinDicSize);
	  m_Dictionary.SetCurSel(0);
	  for (i = 20; i <= 30; i++)
		for (int j = 0; j < 2; j++)
		{
		  if (i == 20 && j > 0)
			continue;
		  UINT32 dictionary = (1 << i) + (j << (i - 1));
		  if (dictionary >
		  #ifdef _WIN64
			(1 << 30)
		  #else
			(1 << 26)
		  #endif
			)
			continue;
		  AddDictionarySize(dictionary);
		  UINT64 decomprSize;
		  UINT64 requiredComprSize = GetMemoryUsage(dictionary, decomprSize);
		  if (dictionary <= defaultDictionary && requiredComprSize <= maxRamSize)
			m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1);
		}

	  // SetNearestSelectComboBox(m_Dictionary, defaultDictionary);
	  break;
	}
	case kPPMd:
	{
	  if (defaultDictionary == (UINT32)-1)
	  {
		if (level >= 9)      defaultDictionary = (192 << 20);
		else if (level >= 7) defaultDictionary = ( 64 << 20);
		else if (level >= 5) defaultDictionary = ( 16 << 20);
		else                 defaultDictionary = (  4 << 20);
	  }
	  int i;
	  for (i = 20; i < 31; i++)
		for (int j = 0; j < 2; j++)
		{
		  if (i == 20 && j > 0)
			continue;
		  UINT32 dictionary = (1 << i) + (j << (i - 1));
		  if (dictionary >
			#ifdef _WIN64
			  (1 << 30)
			#else
			  (1 << 29)
			#endif
			)
			continue;
		  AddDictionarySize(dictionary);
		  UINT64 decomprSize;
		  UINT64 requiredComprSize = GetMemoryUsage(dictionary, decomprSize);
		  if (dictionary <= defaultDictionary && requiredComprSize <= maxRamSize || m_Dictionary.GetCount() == 0)
			m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1);
		}
	  SetNearestSelectComboBox(m_Dictionary, defaultDictionary);
	  break;
	}
	case kDeflate:
	{
	  AddDictionarySize(32 << 10);
	  m_Dictionary.SetCurSel(0);
	  break;
	}
	case kDeflate64:
	{
	  AddDictionarySize(64 << 10);
	  m_Dictionary.SetCurSel(0);
	  break;
	}
	case kBZip2:
	{
	  if (defaultDictionary == (UINT32)-1)
	  {
		if (level >= 5)
		  defaultDictionary = (900 << 10);
		else if (level >= 3)
		  defaultDictionary = (500 << 10);
		else
		  defaultDictionary = (100 << 10);
	  }
	  for (int i = 1; i <= 9; i++)
	  {
		UINT32 dictionary = (i * 100) << 10;
		AddDictionarySize(dictionary);
		if (dictionary <= defaultDictionary || m_Dictionary.GetCount() == 0)
		  m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1);
	  }
	  break;
	}
	case kPPMdZip:
	{
	  if (defaultDictionary == (UINT32)-1)
		defaultDictionary = (1 << (19 + (level > 8 ? 8 : level)));
	  for (int i = 20; i <= 28; i++)
	  {
		UINT32 dictionary = (1 << i);
		AddDictionarySize(dictionary);
		UINT64 decomprSize;
		UINT64 requiredComprSize = GetMemoryUsage(dictionary, decomprSize);
		if (dictionary <= defaultDictionary && requiredComprSize <= maxRamSize || m_Dictionary.GetCount() == 0)
		  m_Dictionary.SetCurSel(m_Dictionary.GetCount() - 1);
	  }
	  SetNearestSelectComboBox(m_Dictionary, defaultDictionary);
	  break;
	}
  }
}

UINT32 CCompressDialog::GetComboValue(CComboBox &c, int defMax)
{
  if (c.GetCount() <= defMax)
	return (UINT32)-1;
  return (UINT32)c.GetItemData(c.GetCurSel());
}

UINT32 CCompressDialog::GetLevel2()
{
  UINT32 level = GetLevel();
  if (level == (UINT32)-1)
	level = 5;
  return level;
}

int CCompressDialog::AddOrder(UINT32 size)
{
  TCHAR s[40];
  _ultot(size, s, 10);
  int index = (int)m_Order.AddString(s);
  m_Order.SetItemData(index, size);
  return index;
}

void CCompressDialog::SetOrder()
{
  m_Order.ResetContent();
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  UINT32 defaultOrder = (UINT32)-1;
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	if (fo.Method.CompareNoCase(GetMethodSpec()) == 0)
	  defaultOrder = fo.Order;
  }
  int methodID = GetMethodID();
  UINT32 level = GetLevel2();
  if (methodID < 0)
	return;
  switch (methodID)
  {
	case kLZMA:
	case kLZMA2:
	{
	  if (defaultOrder == (UINT32)-1)
		defaultOrder = (level >= 7) ? 64 : 32;
	  for (int i = 3; i <= 8; i++)
		for (int j = 0; j < 2; j++)
		{
		  UINT32 order = (1 << i) + (j << (i - 1));
		  if (order <= 256)
			AddOrder(order);
		}
	  AddOrder(273);
	  SetNearestSelectComboBox(m_Order, defaultOrder);
	  break;
	}
	case kPPMd:
	{
	  if (defaultOrder == (UINT32)-1)
	  {
		if (level >= 9)
		  defaultOrder = 32;
		else if (level >= 7)
		  defaultOrder = 16;
		else if (level >= 5)
		  defaultOrder = 6;
		else
		  defaultOrder = 4;
	  }
	  int i;
	  AddOrder(2);
	  AddOrder(3);
	  for (i = 2; i < 8; i++)
		for (int j = 0; j < 4; j++)
		{
		  UINT32 order = (1 << i) + (j << (i - 2));
		  if (order < 32)
			AddOrder(order);
		}
	  AddOrder(32);
	  SetNearestSelectComboBox(m_Order, defaultOrder);
	  break;
	}
	case kDeflate:
	case kDeflate64:
	{
	  if (defaultOrder == (UINT32)-1)
	  {
		if (level >= 9)
		  defaultOrder = 128;
		else if (level >= 7)
		  defaultOrder = 64;
		else
		  defaultOrder = 32;
	  }
	  int i;
	  for (i = 3; i <= 8; i++)
		for (int j = 0; j < 2; j++)
		{
		  UINT32 order = (1 << i) + (j << (i - 1));
		  if (order <= 256)
			AddOrder(order);
		}
	  AddOrder(methodID == kDeflate64 ? 257 : 258);
	  SetNearestSelectComboBox(m_Order, defaultOrder);
	  break;
	}
	case kBZip2:
	{
	  break;
	}
	case kPPMdZip:
	{
	  if (defaultOrder == (UINT32)-1)
		defaultOrder = level + 3;
	  for (int i = 2; i <= 16; i++)
		AddOrder(i);
	  SetNearestSelectComboBox(m_Order, defaultOrder);
	  break;
	}
  }
}

bool CCompressDialog::GetOrderMode()
{
  switch (GetMethodID())
  {
	case kPPMd:
	  return true;
  }
  return false;
}

static const UINT32 kNoSolidBlockSize = 0;
static const UINT32 kSolidBlockSize = 64;

void CCompressDialog::SetSolidBlockSize()
{
  m_Solid.ResetContent();
  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  if (!fi.Solid)
	return;

  UINT32 level = GetLevel2();
  if (level == 0)
	return;

  UINT32 dictionary = GetDictionarySpec();
  if (dictionary == (UINT32)-1)
	dictionary = 1;

  UINT32 defaultBlockSize = (UINT32)-1;

  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	if (fo.Method.CompareNoCase(GetMethodSpec()) == 0)
	  defaultBlockSize = fo.BlockLogSize;
  }

  int nResult = (int)m_Solid.AddString(Lang::LangString(IDS_COMPRESS_NON_SOLID, 0x02000D14)) ;
  
  m_Solid.SetItemData(nResult, (UINT32)kNoSolidBlockSize);
  m_Solid.SetCurSel(0);
  bool needSet = defaultBlockSize == (UINT32)-1;
  for (int i = 20; i <= 36; i++)
  {
	if (needSet && dictionary >= (((UINT64)1 << (i - 7))) && i <= 32)
	  defaultBlockSize = i;
	TCHAR s[40];
	_ultot(1 << (i % 10), s, 10);
	if (i < 30) lstrcat(s, TEXT(" M"));
	else        lstrcat(s, TEXT(" G"));
	lstrcat(s, TEXT("B"));
	int index = (int)m_Solid.AddString(s);
	m_Solid.SetItemData(index, (UINT32)i);
  }
  nResult = (int)m_Solid.AddString(Lang::LangString(IDS_COMPRESS_SOLID, 0x02000D15));
  m_Solid.SetItemData(nResult, kSolidBlockSize);
  if (defaultBlockSize == (UINT32)-1)
	defaultBlockSize = kSolidBlockSize;
  if (defaultBlockSize != kNoSolidBlockSize)
	SetNearestSelectComboBox(m_Solid, defaultBlockSize);
}

void CCompressDialog::SetNumThreads()
{
  m_NumThreads.ResetContent();

  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  if (!fi.MultiThread)
	return;

  UINT32 numHardwareThreads = System::GetNumberOfProcessors();
  UINT32 defaultValue = numHardwareThreads;

  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  size_t index = FindRegistryFormat(ai.Name);
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	if (fo.Method.CompareNoCase(GetMethodSpec()) == 0 && fo.NumThreads != (UINT32)-1)
	  defaultValue = fo.NumThreads;
  }

  UINT32 numAlgoThreadsMax = 1;
  int methodID = GetMethodID();
  switch (methodID)
  {
	case kLZMA: numAlgoThreadsMax = 2; break;
	case kLZMA2: numAlgoThreadsMax = 32; break;
	case kBZip2: numAlgoThreadsMax = 32; break;
  }
  if (IsZipFormat())
	numAlgoThreadsMax = 128;
  for (UINT32 i = 1; i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++)
  {
	TCHAR s[40];
	_ultot(i, s, 10);
	int index = (int)m_NumThreads.AddString(s);
	m_NumThreads.SetItemData(index, (UINT32)i);
  }
  SetNearestSelectComboBox(m_NumThreads, defaultValue);
}

UINT64 CCompressDialog::GetMemoryUsage(UINT32 dictionary, UINT64 &decompressMemory)
{
  decompressMemory = UINT64(INT64(-1));
  UINT32 level = GetLevel2();
  if (level == 0)
  {
	decompressMemory = (1 << 20);
	return decompressMemory;
  }
  UINT64 size = 0;

  const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
  if (fi.Filter && level >= 9)
	size += (12 << 20) * 2 + (5 << 20);
  UINT32 numThreads = GetNumThreads2();
  if (IsZipFormat())
  {
	UINT32 numSubThreads = 1;
	if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5)
	  numSubThreads = 2;
	UINT32 numMainThreads = numThreads / numSubThreads;
	if (numMainThreads > 1)
	  size += (UINT64)numMainThreads << 25;
  }
  int methidId = GetMethodID();
  switch (methidId)
  {
	case kLZMA:
	case kLZMA2:
	{
	  UINT32 hs = dictionary - 1;
	  hs |= (hs >> 1);
	  hs |= (hs >> 2);
	  hs |= (hs >> 4);
	  hs |= (hs >> 8);
	  hs >>= 1;
	  hs |= 0xFFFF;
	  if (hs > (1 << 24))
		hs >>= 1;
	  hs++;
	  UINT64 size1 = (UINT64)hs * 4;
	  size1 += (UINT64)dictionary * 4;
	  if (level >= 5)
		size1 += (UINT64)dictionary * 4;
	  size1 += (2 << 20);

	  UINT32 numThreads1 = 1;
	  if (numThreads > 1 && level >= 5)
	  {
		size1 += (2 << 20) + (4 << 20);
		numThreads1 = 2;
	  }
	  UINT32 numBlockThreads = numThreads / numThreads1;
	  if (methidId == kLZMA || numBlockThreads == 1)
		size1 += (UINT64)dictionary * 3 / 2;
	  else
	  {
		UINT64 chunkSize = (UINT64)dictionary << 2;
		chunkSize = max(chunkSize, (UINT64)(1 << 20));
		chunkSize = min(chunkSize, (UINT64)(1 << 28));
		chunkSize = max(chunkSize, (UINT64)dictionary);
		size1 += chunkSize * 2;
	  }
	  size += size1 * numBlockThreads;

	  decompressMemory = dictionary + (2 << 20);
	  return size;
	}
	case kPPMd:
	{
	  decompressMemory = dictionary + (2 << 20);
	  return size + decompressMemory;
	}
	case kDeflate:
	case kDeflate64:
	{
	  UINT32 order = GetOrder();
	  if (order == (UINT32)-1)
		order = 32;
	  if (level >= 7)
		size += (1 << 20);
	  size += 3 << 20;
	  decompressMemory = (2 << 20);
	  return size;
	}
	case kBZip2:
	{
	  decompressMemory = (7 << 20);
	  UINT64 memForOneThread = (10 << 20);
	  return size + memForOneThread * numThreads;
	}
	case kPPMdZip:
	{
	  decompressMemory = dictionary + (2 << 20);
	  return size + (UINT64)decompressMemory * numThreads;
	}
  }
  return (UINT64)(INT64)-1;
}

UINT64 CCompressDialog::GetMemoryUsage(UINT64 &decompressMemory)
{
  return GetMemoryUsage(GetDictionary(), decompressMemory);
}

void CCompressDialog::PrintMemUsage(UINT res, UINT64 value)
{
  if (value == (UINT64)(INT64)-1)
  {
	SetDlgItemText(res, TEXT("?"));
	return;
  }
  value = (value + (1 << 20) - 1) >> 20;
  TCHAR s[40];
  _ui64tot(value, s, 10);
  lstrcat(s, TEXT(" MB"));
  SetDlgItemText(res, s);
}
	
void CCompressDialog::SetMemoryUsage()
{
  UINT64 decompressMem;
  UINT64 memUsage = GetMemoryUsage(decompressMem);
  PrintMemUsage(IDC_STATIC_COMPRESS_MEMORY_VALUE, memUsage);
  PrintMemUsage(IDC_STATIC_COMPRESS_MEMORY_DE_VALUE, decompressMem);
}

void CCompressDialog::SetParams()
{
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[GetFormatIndex()];
  m_Params.SetWindowText(TEXT(""));
  size_t index = FindRegistryFormat(ai.Name);
  if (index != -1)
  {
	const Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
	m_Params.SetWindowText(fo.Options);
  }
}

void CCompressDialog::SaveOptionsInMem()
{
  const Common::Archive::CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
  size_t index = FindRegistryFormatAlways(ai.Name);
  m_Params.GetWindowText(Info.Options);
  Info.Options.Trim();
  Common::Archive::Compression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
  fo.Options = Info.Options;
  fo.Level = GetLevelSpec();
  fo.Dictionary = GetDictionarySpec();
  fo.Order = GetOrderSpec();
  fo.Method = GetMethodSpec();
  fo.EncryptionMethod = GetEncryptionMethodSpec();
  fo.NumThreads = GetNumThreadsSpec();
  fo.BlockLogSize = GetBlockSizeSpec();
}

int CCompressDialog::GetFormatIndex()
{
  return (int)m_Format.GetItemData(m_Format.GetCurSel());
}
